package com.hornet.manager.weixin.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

public class HttpUtil {

	public static void main(String[] args) throws ClientProtocolException,
			IOException {
		long start = System.currentTimeMillis();

		//String doGet = HttpUt.doGet("http://www.itjie.cc/index.php", null);
		//System.out.println(doGet);
		
		String doPost = HttpUtil.doPost("http://www.itjie.cc/index.php", null);
		System.out.println(doPost);

		long end = System.currentTimeMillis();
		System.out.println("耗时----> " + (end - start));
	}
	
	/**
	 * 发送GET请求
	 * @param url    请求的地址
	 * @return
	 */
	public static String doGet(String url) {
		return doGet(url, null);
	}

	/**
	 * 发送GET请求
	 * @param url    请求的地址
	 * @return
	 */
	public static InputStream doGetInputStream(String url) {
		return doGetInputStream(url, null);
	}

	/**
	 * 发送GET请求
	 * @param url    请求的地址
	 * @param params 请求的参数
	 * @return InputStream
	 */
	public static InputStream doGetInputStream(String url, Map<String, Object> params) {
		HttpGet httpGet = null;
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		
		try {
			if (null != params && !params.isEmpty()) {
				StringBuffer param = new StringBuffer();
				int i = 0;
				for (String key : params.keySet()) {
					if (i == 0)
						param.append("?");
					else
						param.append("&");
					param.append(key).append("=").append(params.get(key));
					i++;
				}
				url += param;
			}
			
			httpClient = getHttpClient();
			httpGet = new HttpGet(url);
			response = httpClient.execute(httpGet);
			
			int statusCode = response.getStatusLine().getStatusCode();
			
			if (statusCode >= 200 && statusCode < 300) {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					return entity.getContent();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != httpGet) {
				try {
					httpGet.clone();
				} catch (CloneNotSupportedException e) {
					e.printStackTrace();
				}
			}
			if (null != response) {
				try {
					response.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != httpClient) {
				try {
					httpClient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}
	/**
	 * 发送GET请求
	 * @param url    请求的地址
	 * @param params 请求的参数
	 * @return String
	 */
	public static String doGet(String url, Map<String, Object> params) {
		HttpGet httpGet = null;
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;

		try {
			if (null != params && !params.isEmpty()) {
				StringBuffer param = new StringBuffer();
				int i = 0;
				for (String key : params.keySet()) {
					if (i == 0)
						param.append("?");
					else
						param.append("&");
					param.append(key).append("=").append(params.get(key));
					i++;
				}
				url += param;
			}

			httpClient = getHttpClient();
			httpGet = new HttpGet(url);
			response = httpClient.execute(httpGet);

			int statusCode = response.getStatusLine().getStatusCode();

			if (statusCode >= 200 && statusCode < 300) {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					return EntityUtils.toString(entity, "UTF-8");
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != httpGet) {
				try {
					httpGet.clone();
				} catch (CloneNotSupportedException e) {
					e.printStackTrace();
				}
			}
			if (null != response) {
				try {
					response.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != httpClient) {
				try {
					httpClient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}

	/**
	 * 发送POST请求
	 * @param url 请求的地址
	 * @return    返回请求的内容
	 */
	public static String doPost(String url) {
		return doPost(url, null) ;
	}
	/**
	 * 发送POST请求
	 * @param url    请求的地址
	 * @param params 请求的参数
	 * @return 返回请求的内容
	 */
	public static String doPost(String url, Map<String, Object> params) {
		HttpPost httpPost = null;
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		
		try {
			httpClient = getHttpClient();
			httpPost = new HttpPost(url) ;
			
			if(null != params && !params.isEmpty()) {
				List<NameValuePair> pairList = new ArrayList<>(params.size());  
				for (Map.Entry<String, Object> entry : params.entrySet()) {  
					NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry  
							.getValue().toString());  
					pairList.add(pair);  
				}  
				httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8")));  
			}
			
			response = httpClient.execute(httpPost);
			
			int statusCode = response.getStatusLine().getStatusCode();
			
			if (statusCode >= 200 && statusCode < 300) {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					return EntityUtils.toString(entity, "UTF-8");
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != httpPost) {
				try {
					httpPost.clone();
				} catch (CloneNotSupportedException e) {
					e.printStackTrace();
				}
			}
			if (null != response) {
				try {
					response.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != httpClient) {
				try {
					httpClient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}
	
	/**
	 * 发送POST请求，以JSON方式
	 * @param url  请求的地址
	 * @param json JSON格式字符串
	 * @return 返回请求到的内容
	 */
	public static String doPost(String url, Object json) {
		HttpPost httpPost = null;
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;

		try {
			httpClient = getHttpClient();
			httpPost = new HttpPost(url) ;
			httpPost.addHeader("Content-Type", "application/json");
			StringEntity stringEntity = new StringEntity(json.toString(), ContentType.create("application/json", "UTF-8")) ;
			httpPost.setEntity(stringEntity); 
			
			response = httpClient.execute(httpPost);
			
			int statusCode = response.getStatusLine().getStatusCode();
			
			if (statusCode >= 200 && statusCode < 300) {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					return EntityUtils.toString(entity, "UTF-8");
				}
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != httpPost) {
				try {
					httpPost.clone();
				} catch (CloneNotSupportedException e) {
					e.printStackTrace();
				}
			}
			if (null != response) {
				try {
					response.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != httpClient) {
				try {
					httpClient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}

	public static CloseableHttpClient getHttpClient() {
		try {
			SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(
					null, new TrustStrategy() {
						// 信任所有
						public boolean isTrusted(X509Certificate[] chain,
								String authType) throws CertificateException {
							return true;
						}
					}).build();
			// SSL
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
					sslContext);

			ConnectionSocketFactory plainsf = PlainConnectionSocketFactory
					.getSocketFactory();
			Registry<ConnectionSocketFactory> registry = RegistryBuilder
					.<ConnectionSocketFactory> create()
					.register("http", plainsf).register("https", sslsf).build();
			PoolingHttpClientConnectionManager cmPoolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(
					registry);
			cmPoolingHttpClientConnectionManager.setMaxTotal(200); // 将最大连接数增加到200
			cmPoolingHttpClientConnectionManager.setDefaultMaxPerRoute(20); // 将每个路由基础的连接增加到20

			// 请求重试处理
			HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
				public boolean retryRequest(IOException exception,
						int executionCount, HttpContext context) {
					System.out.println(executionCount);
					if (executionCount >= 5) {// 如果已经重试了5次，就放弃
						return false;
					}
					if (exception instanceof NoHttpResponseException) { // 如果服务器丢掉了连接，那么就重试
						return true;
					}
					if (exception instanceof SSLHandshakeException) { // 不要重试SSL握手异常
						return false;
					}
					if (exception instanceof InterruptedIOException) { // 超时
						return false;
					}
					if (exception instanceof UnknownHostException) { // 目标服务器不可达
						return false;
					}
					if (exception instanceof ConnectTimeoutException) { // 连接被拒绝
						return false;
					}
					if (exception instanceof SSLException) { // ssl握手异常
						return false;
					}

					HttpClientContext clientContext = HttpClientContext
							.adapt(context);
					HttpRequest request = clientContext.getRequest();
					// 如果请求是幂等的，就再次尝试
					if (!(request instanceof HttpEntityEnclosingRequest)) {
						return true;
					}
					return false;
				}
			};

			CloseableHttpClient httpclient = HttpClients.custom()
					.setConnectionManager(cmPoolingHttpClientConnectionManager)
					.setRetryHandler(httpRequestRetryHandler).build();

			return httpclient;
		} catch (KeyManagementException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (KeyStoreException e) {
			e.printStackTrace();
		}
		return null;
	}

}
